import { clone } from 'src/utils/object'

export class Queue {
  // jobHandler - function(job): Promise
  // errHandler - function(err, job): undefined
  constructor(jobHandler, errHandler = NopErrHandler) {
    this.errHandler = errHandler
    this.jobHandler = jobHandler
    this.consuming = false
    this.jobs = []
  }

  enqueue(job) {
    this.jobs.push(job)
    this.startConsumingQueue()
  }

  dequeue() {
    const n = this.jobs.length
    if (n === 0) {
      return EOQ
    }
    return this.jobs.shift()
  }

  async startConsumingQueue() {
    if (this.consuming) {
      // the consuming loop already started, do nothing
      return
    }

    this.consuming = true

    let job
    while ((job = this.dequeue()) !== EOQ) {
      try {
        await this.jobHandler(job)
      } catch (e) {
        this.errHandler(e, job)
      }
    }

    this.consuming = false
  }
}

export class RateLimitingQueue extends Queue {
  // dequeue gets last job in queue, returns EOQ if queue is empty
  dequeue() {
    const n = this.jobs.length
    if (n === 0) {
      return EOQ
    }

    const job = this.jobs[n - 1]
    this.jobs.splice(0, n)

    return job
  }
}

// End of Queue
function EOQ() {}
function NopErrHandler(err) {}
